package it.dk.model;

import java.util.ArrayList;

/**
 * Classe per il rilevamento delle collisioni tra hero
 * e i vari oggetti del gioco
 */
public class CollisionManager {

	private Game game;
	private AlertCollisionHero alertCollisionHero;
	private AlertCollisionBarrelPlatform alertCollisionBarrelPlatform;
	private AlertCollisionBarrelLeftBorder alertCollisionBarrelBorder;
	private ArrayList<Integer> barrelPlatform,barrelBorder,heroObjects;

	/* posizioni dei differenti oggetti all'interno dell'array  heroObjects*/
	private static final int INDEX_PLATFORM_POSITION = 0;
	private static final int INDEX_PLATFORM_UP_POSITION = 1;
	private static final int INDEX_BARREL_POSITION = 2;
	private static final int INDEX_LADDER_POSITION = 3;
	private static final int INDEX_LADDER_UP_POSITION = 4;
	private static final int INDEX_LADDER_DOWN_POSITION = 5;
	private static final int INDEX_BORDER_LEFT_POSITION = 6;
	private static final int INDEX_BORDER_RIGHT_POSITION = 7;
	private static final int INDEX_PRINCESS = 8;
	private static final int INDEX_POINT_GATE = 9;
	private static final int NOT_COLLISION = -1;
	private static final int COLLISION = 1;
	

	/**
	 * Costruttore della classe
	 * 
	 * @param game	oggetto di tipo Game dal quale vengono prelevati tutti gli oggetti
	 */
	public CollisionManager(Game game) {
		this.game = game;
		alertCollisionBarrelPlatform = new AlertCollisionBarrelPlatform(
				game.getMaxBarrels());
		alertCollisionHero = new AlertCollisionHero(game.getObjectsCollision());
		alertCollisionBarrelBorder = new AlertCollisionBarrelLeftBorder(game.getMaxBarrels());
		
		/*
		 * dichiarazione e inizializzazione degli array per identificare le
		 * collisioni
		 */
		barrelPlatform = new ArrayList<Integer>(
				game.getObjectsCollision());
		barrelBorder = new ArrayList<Integer>(
				game.getMaxBarrels());
		heroObjects = new ArrayList<Integer>(game.getMaxBarrels());

		for (int i = 0; i < game.getMaxBarrels(); i++)
			barrelPlatform.add(NOT_COLLISION);
		for (int i = 0; i < game.getMaxBarrels(); i++)
			barrelBorder.add(NOT_COLLISION);
		for (int i = 0; i < game.getObjectsCollision(); i++)
			heroObjects.add(NOT_COLLISION);

	}

	/**
	 * Metodo per il rilevamento e aggiornamento dello stato delle collisioni
	 */
	public void update() {

		// contorlliamo la collisione fra hero e principessa
		if (game.getPrincess().collidesWith(game.getHero().getInnerShape()))
			heroObjects.set(INDEX_PRINCESS, COLLISION);
		else
			heroObjects.set(INDEX_PRINCESS, NOT_COLLISION);
		
		// cotrolliamo le collisioni tra hero e i vari Barrel
		for (int i = 0; i < game.getBarrels().size(); i++) {
			if (game.getBarrels().get(i).collidesWith(game.getHero().getInnerShape())) {
				heroObjects.set(INDEX_BARREL_POSITION, i);
				break;
			}
			else
				heroObjects.set(INDEX_BARREL_POSITION, NOT_COLLISION);
		}
		
		// cotrolliamo le collisioni tra hero e i vari Barrel
		for (int i = 0; i < game.getBarrels().size(); i++) {
			if (game.getBarrels().get(i).getUpperGate().intersects(game.getHero().getInnerShape())) {
				heroObjects.set(INDEX_POINT_GATE, i);
				break;
			}
			else
				heroObjects.set(INDEX_POINT_GATE, NOT_COLLISION);
		}

		// cotrolliamo le collisioni tra hero e le varie Platform
		for (int i = 0; i < game.getPlatforms().size(); i++) {
			if (game.getPlatforms().get(i).collidesWith(game.getHero().getBottomBorder())) {
				heroObjects.set(INDEX_PLATFORM_POSITION, i);
				
				if(game.getPlatforms().get(i).getUpperBorder().intersects(game.getHero().getBottomBorder()))
					heroObjects.set(INDEX_PLATFORM_UP_POSITION, i);
				else
					heroObjects.set(INDEX_PLATFORM_UP_POSITION, NOT_COLLISION);
				
				break;
			}
			else{
				heroObjects.set(INDEX_PLATFORM_POSITION, NOT_COLLISION);
				heroObjects.set(INDEX_PLATFORM_UP_POSITION, NOT_COLLISION);
			}
		}

		// cotrolliamo le collisioni tra hero e i vari Ladder
		for (int i = 0; i < game.getLadders().size(); i++) {
			if (game.getLadders().get(i).collidesWith(game.getHero().getBottomBorder())) {
				heroObjects.set(INDEX_LADDER_POSITION, i);
				
				if(game.getLadders().get(i).getBottomBorder().intersects(game.getHero().getBottomBorder()))
					heroObjects.set(INDEX_LADDER_DOWN_POSITION, i);
				else
					heroObjects.set(INDEX_LADDER_DOWN_POSITION, NOT_COLLISION);
				
				if(game.getLadders().get(i).getTopBorder().intersects(game.getHero().getBottomBorder()))
					heroObjects.set(INDEX_LADDER_UP_POSITION, i);
				else
					heroObjects.set(INDEX_LADDER_UP_POSITION, NOT_COLLISION);
				
				break;
			}
			else{
				heroObjects.set(INDEX_LADDER_POSITION, NOT_COLLISION);
				heroObjects.set(INDEX_LADDER_DOWN_POSITION, NOT_COLLISION);
				heroObjects.set(INDEX_LADDER_UP_POSITION, NOT_COLLISION);
			}
		}

		// cotrolliamo le collisioni tra hero e LeftBorder
		if (game.getLeftBorder().collidesWith(game.getHero().shape))
			heroObjects.set(INDEX_BORDER_LEFT_POSITION, COLLISION);
		else
			heroObjects.set(INDEX_BORDER_LEFT_POSITION, NOT_COLLISION);

		// cotrolliamo le collisioni tra hero e RightBorder
		if (game.getRightBorder().collidesWith(game.getHero().shape))
			heroObjects.set(INDEX_BORDER_RIGHT_POSITION, COLLISION);
		else
			heroObjects.set(INDEX_BORDER_RIGHT_POSITION, NOT_COLLISION);

		
		// controlliamo le collisioni tra i barili e le varie piattaforme
		for (int i = 0; i < game.getMaxBarrels(); i++) {
			// Se i è minore del numero di barili al momento instanziati procede 
			// altrimenti imposta il resto a NOT_COLLISION
			if (i < game.getBarrels().size()) {
				for (int j = 0; j < game.getPlatforms().size(); j++) {
					if (game.getPlatforms().get(j).collidesWith(game.getBarrels().get(i).getShape())) {
						barrelPlatform.set(i, j);
						break;
					} else
						barrelPlatform.set(i, NOT_COLLISION);

				}
			}
			else
				barrelPlatform.set(i, NOT_COLLISION);
		}
		
		// controlliamo le collisioni tra i barili e il bordo sinistro
		for (int i = 0; i < game.getMaxBarrels(); i++) {
			// Se i è minore del numero di barili al momento instanziati procede 
			// altrimenti imposta il resto a NOT_COLLISION
			if (i < game.getBarrels().size()) {
				// se il barile collide ci metto COLLISION altrimenti NOT_COLLISION
					if (game.getBarrels().get(i).collidesWith(game.getLeftBorder().getShape())) {
						barrelBorder.set(i, COLLISION);
					} else
						barrelBorder.set(i, NOT_COLLISION);

				
			}
			else
				barrelBorder.set(i, NOT_COLLISION);
		}

		alertCollisionHero.setCollision(heroObjects);
		alertCollisionBarrelPlatform.setCollision(barrelPlatform);
		alertCollisionBarrelBorder.setCollision(barrelBorder);
	}

	/**
	 * Metodo getter per INDEX_LADDER_UP_POSITION
	 * 
	 * @return la costante INDEX_LADDER_UP_POSITION
	 */
	public static int getIndexLadderUpPosition() {
		return INDEX_LADDER_UP_POSITION;
	}

	/**
	 * Metodo getter per INDEX_LADDER_DOWN_POSITION
	 * 
	 * @return la costante INDEX_LADDER_DOWN_POSITION
	 */
	public static int getIndexLadderDownPosition() {
		return INDEX_LADDER_DOWN_POSITION;
	}

	/**
	 * Metodo getter per l'oggetto di tipo game
	 * che contiene tutte le componenti della board
	 * 
	 * @return game	oggetto di tipo game da restituire
	 */
	public Game getGame() {
		return game;
	}

	/**
	 * Metodo getter per l'oggetto collisione di hero
	 * 
	 * @return oggetto collisione di hero
	 */
	public AlertCollisionHero getAcHero() {
		return alertCollisionHero;
	}

	/**
	 * Metodo getter per INDEX_PLATFORM_POSITION
	 * 
	 * @return la costante INDEX_PLATFORM_POSITION
	 */
	public static int getIndexPlatformPosition() {
		return INDEX_PLATFORM_POSITION;
	}

	/**
	 * Metodo getter per INDEX_PLATFORM_UP_POSITION
	 * 
	 * @return la costante INDEX_PLATFORM_UP_POSITION
	 */
	public static int getIndexPlatformUpPosition(){
		return INDEX_PLATFORM_UP_POSITION;
	}
	
	/**
	 * Metodo getter per INDEX_BARREL_POSITION
	 * 
	 * @return la costante INDEX_BARREL_POSITION
	 */
	public static int getIndexBarrelPosition() {
		return INDEX_BARREL_POSITION;
	}
	
	/**
	 * Metodo getter per INDEX_LADDER_POSITION
	 * 
	 * @return la costante INDEX_LADDER_POSITION
	 */
	public static int getIndexLadderPosition() {
		return INDEX_LADDER_POSITION;
	}

	/**
	 * Metodo getter per INDEX_BORDER_LEFT_POSITION
	 * 
	 * @return la costante INDEX_BORDER_LEFT_POSITION
	 */
	public static int getIndexBorderLeftPosition() {
		return INDEX_BORDER_LEFT_POSITION;
	}

	/**
	 * Metodo getter per INDEX_BORDER_RIGHT_POSITION
	 * 
	 * @return la costante INDEX_BORDER_RIGHT_POSITION
	 */
	public static int getIndexBorderRightPosition() {
		return INDEX_BORDER_RIGHT_POSITION;
	}
	
	/**
	 * Metodo getter per INDEX_PRINCESS
	 * 
	 * @return la costante INDEX_PRINCESS
	 */
	public static int getIndexPrincess() {
		return INDEX_PRINCESS;
	}

	/**
	 * Metodo setter per l'oggetto di tipo game
	 * che contiene tutte le componenti della board
	 * 
	 * @param game	oggetto di tipo game da settare
	 */
	public void setGame(Game game) {
		this.game = game;
	}
	

	/**
	 * Metodo getter per NOT_COLLISION
	 * 
	 * @return la costante NOT_COLLISION
	 */
	public static int getNotCollision() {
		return NOT_COLLISION;
	}

	/**
	 * Metodo getter per COLLISION
	 * 
	 * @return la costante COLLISION
	 */
	public static int getCollision() {
		return COLLISION;
	}

	/**
	 * Metodo getter per l'oggetto collisione tra barile e piattaforma
	 * 
	 * @return oggetto collisione tra barile e piattaforma
	 */
	public AlertCollisionBarrelPlatform getAcBarrelPlatform() {
		return alertCollisionBarrelPlatform;
	}

	/**
	 * Metodo getter per l'oggetto collisione tra barile e bordo sinistro
	 * 
	 * @return oggetto collisione tra barile e bordo sinistro
	 */
	public AlertCollisionBarrelLeftBorder getAcBarrelBorder() {
		return alertCollisionBarrelBorder;
	}
	
	/**
	 * Metodo getter per INDEX_POINT_GATE
	 * 
	 * @return la costante INDEX_POINT_GATE
	 */
	public static int getIndexPointGate() {
		return INDEX_POINT_GATE;
	}
}
